log = require '../log'
error = require '../error'

SystemService = require '../service/SystemService'
EntityService = require '../service/EntityService'
UserService = require '../service/UserService'

anonymous = {role: ["anonymous"]}

exports.gIdentifyUser = (next)->
    host = @request.host # TODO 验证是domain:port的格式
    # log.debug 'verify user, request host: ' + host
    server = yield from EntityService.gFindOneByCriteria({}, null, 'F_Server', {host: host})
    throw new error.UserError("NoSuchServer", "未配置服务器：" + host) unless server

    @state.subApp = server.app

    trackId = @cookies.get(server.app + 'TID', {signed: true})
    @state.trackId = trackId

    userId = @cookies.get(server.app + 'UserId', {signed: true})
    userToken = @cookies.get(server.app + 'UserToken', {signed: true})

    if userId && userToken
        try
            user = yield from UserService.gAuthToken(server.app, userId, userToken)
            # log.debug 'auth token: ', user
            @state.user = user if user
        catch e
            false

    yield next

exports.gControlAccess = (next)->
    pass = yield from gCheckAll @route, @state, @request.url
    log.debug 'access denied' unless pass
    unless pass
        if @state.user?
            throw new error.Error403()
        else
            throw new error.Error401()

    yield next

exports.gControlEntityAccess = (next)->
    user = @state.user
    unless yield from gCheckUserCanAccessEntity user || anonymous, @route.info?.action, @params.entityName
        if @state.user?
            throw new error.Error403()
        else
            throw new error.Error401()
    yield next

gCheckAll = (route, state, url)->
    action = route.info?.action
    return true unless action # 全局可访问的，如登录

    user = state.user
    return true if user?.admin

    return true if action == 'None' and user?

    unless yield from gCheckUserCanAccessSubApp user || anonymous, state.subApp
        log.debug 'Cannot access this sub app', state.subApp, url
        return false

    unless yield from gCheckUserCanAccessUrl user || anonymous, action
        log.debug 'Cannot access this url', action, url
        return false

    true

gCheckUserCanAccessSubApp = (user, subApp)->
    # log.debug 'user subAppAccessible', user.subAppAccessible
    if user.subAppAccessible?[subApp]
        return true

    roles = user.roles
    if roles
        for roleId in roles
            role = yield from UserService.gRoleById roleId
            # log.debug 'role subAppAccessible', role?.subAppAccessible
            if role?.subAppAccessible?[subApp]
                return true

    false

gCheckUserCanAccessUrl = (user, action)->
    if user.urlPermissions?[action]
        return true

    roles = user.roles
    if roles
        for roleId in roles
            role = yield from UserService.gRoleById roleId
            if role?.urlPermissions?[action]
                return true

    false

gCheckUserCanAccessEntity = (user, action, entity)->
    return true if user?.admin || action

    uPs = user.entityPermissions
    if uPs and uPs["#{action}/#{entity}"] || uPs[action + "/*"] || uPs["*/" + entity]
        return true

    roles = user.roles
    if roles
        for roleId in roles
            role = yield from UserService.gRoleById roleId
            rPs = role?.entityPermissions
            if rPs and rPs["#{action}/#{entity}"] || rPs[action + "/*"] || rPs["*/" + entity]
                return true

    false
